home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / lib / udev / fix-persistent-net.pl next >
Perl Script  |  2008-10-24  |  5KB  |  186 lines

  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6.  
  7. my $RULES = "/etc/udev/rules.d/70-persistent-net.rules";
  8.  
  9.  
  10. #-----------------------------------------------------------------------------#
  11. # Sanity check
  12. #-----------------------------------------------------------------------------#
  13. die "$RULES does not exist to fix\n" unless -f $RULES;
  14.  
  15.  
  16. #-----------------------------------------------------------------------------#
  17. # Parse existing /etc/udev/rules.d/70-persistent-net.rules
  18. #-----------------------------------------------------------------------------#
  19.  
  20. open RULES, $RULES
  21.     or die "Unable to open $RULES: $!";
  22.  
  23. my @rules;
  24. while (<RULES>) {
  25.     # Rules may cross multiple lines when lines ends in \
  26.     while (/\\$/ && (my $extra = <RULES>)) {
  27.     $_ .= $extra;
  28.     }
  29.  
  30.     # Skip lines that are empty, have only whitespace and/or comments
  31.     if (/^\s*(\#.*)?$/) {
  32.     push @rules, [ $_ ];
  33.     next;
  34.     }
  35.  
  36.     # Parse rule elements
  37.     my $rule = [];
  38.     while (/(?:([\s,]*)((\S*?)\s*(==|\+=|!=|:=|=)\s*\"([^\"]*)\")|(.+))/gs) {
  39.     if (defined $1) {
  40.         push @{$rule}, $1 if length $1;
  41.         push @{$rule}, {    
  42.         'text' => $2,
  43.         'key' => $3,
  44.         'op' => $4,
  45.         'val' => $5
  46.         };
  47.     } else {
  48.         push @{$rule}, $6;
  49.     }
  50.     }
  51.  
  52.     push @rules, $rule;
  53. }
  54.  
  55. close RULES
  56.     or warn "Error while closing $RULES: $!";
  57.  
  58.  
  59. #-----------------------------------------------------------------------------#
  60. # Fix rule entries
  61. #-----------------------------------------------------------------------------#
  62.  
  63. RULE: foreach my $rule (@rules) {
  64.     my $has_rule = 0;
  65.     my $has_match = 0;
  66.     my $has_type = 0;
  67.     my $name_idx = -1;
  68.     my $name;
  69.     my $address;
  70.  
  71.     MATCH: foreach my $idx (0..$#{$rule}) {
  72.     my $match = $rule->[$idx];
  73.     next unless ref $match;
  74.     $has_rule = 1;
  75.  
  76.     if ($match->{key} =~ /^ATTRS?{type}$/) {
  77.         # Rule matches on interface type
  78.         $has_type = 1;
  79.     } elsif ($match->{key} =~ /^ATTRS?{address}$/) {
  80.         # Rule matches on MAC address
  81.         $has_match = 1;
  82.         $address = $match->{val};
  83.     } elsif ($match->{key} =~ /^ATTRS?{[^}]*}|ENV{[^}]*}|KERNELS$/) {
  84.         # Rule matches on a possibly unique attribute
  85.         $has_match = 1;
  86.     } elsif ($match->{key} =~ /^NAME$/ && $match->{op} =~ /^:?=$/) {
  87.         # Name setting
  88.         $name_idx = $idx;
  89.         $name = $match->{val};
  90.     }
  91.     }
  92.  
  93.     next unless $has_rule;
  94.  
  95.     # Comment out lines that don't match a device by any potentially unique
  96.     # property, since they'll match everything
  97.     unless ($has_match) {
  98.     unshift @{$rule}, "#removed by upgrade, will match any device\n# ";
  99.     $name_idx++;
  100.     }
  101.  
  102.     # Add a match on type for any rule missing that to avoid matching
  103.     # "master" devices
  104.     unless ($has_type) {
  105.     my $type;
  106.  
  107.     # Make sure that the device currently has the "1" (Ethernet) type
  108.     if (-f "/sys/class/net/$name/type"
  109.         && `cat /sys/class/net/$name/type` =~ /^1\s*$/) {
  110.         # It does
  111.         $type = "1";
  112.     } elsif (defined $address) {
  113.         # It doesn't, it's possible that we've already renamed it to
  114.         # something else and a device exists with the right MAC address
  115.         # and a different name
  116.         opendir NET, "/sys/class/net"
  117.         or die "Unable to open /sys/class/net: $!";
  118.  
  119.         my $found = 0;
  120.         while (my $dev = readdir(NET)) {
  121.         next if $dev =~ /^\./;
  122.         next unless (-f "/sys/class/net/$dev/address"
  123.                  && `cat /sys/class/net/$dev/address` =~ /^$address\s*$/i);
  124.         $found = 1;
  125.  
  126.         next unless (-f "/sys/class/net/$dev/type"
  127.                  && `cat /sys/class/net/$dev/type` =~ /^1\s*$/);
  128.  
  129.         # Found a device with a matching address and the right type
  130.         $type = "1";
  131.         }
  132.  
  133.         closedir NET
  134.         or die "Error while closing /sys/class/net: $!";
  135.  
  136.         # No device with the matching MAC address found (unplugged?)
  137.         # stick type in anyway
  138.         $type = "1" unless $found;
  139.     }
  140.     
  141.     # Append a rule to match the type.  If we couldn't find an Ethernet
  142.     # device with the set name, or a different name but the right address,
  143.     # then we don't attempt to change the file and instead leave a comment
  144.     # to highlight a line that might be a problem.
  145.     if (defined $type) {
  146.         my $match = {
  147.         'text' => "ATTR{type}==\"$type\"",
  148.         'key' => 'ATTR{type}',
  149.         'op' => '==',
  150.         'val' => "$type"
  151.         };
  152.         splice(@{$rule}, $name_idx, 0, $match, ", ");
  153.         $name_idx += 2;
  154.     } elsif ($has_match) {
  155.         unshift @{$rule}, "#following line may cause a device to become stuck as ${name}_rename\n#add ADDR{type}==\"...\" if that happens\n";
  156.         $name_idx++;
  157.     }
  158.     }
  159. }
  160.  
  161.  
  162. #-----------------------------------------------------------------------------#
  163. # Write new /etc/udev/rules.d/70-persistent-net.rules
  164. #-----------------------------------------------------------------------------#
  165.  
  166. open RULES, ">$RULES.new"
  167.     or die "Unable to open $RULES.new: $!";
  168.  
  169. foreach my $rule (@rules) {
  170.     my $line = "";
  171.     foreach my $match (@{$rule}) {
  172.     if (ref $match) {
  173.         $line .= $match->{text};
  174.     } else {
  175.         $line .= $match;
  176.     }
  177.     }
  178.  
  179.     print RULES $line;
  180. }
  181.  
  182. close RULES
  183.     or warn "Error while closing $RULES: $!";
  184. rename "$RULES.new", $RULES
  185.     or die "Unable to replace $RULES: $!";
  186.